循环冗余校验(CRC)【C语言 位运算】
【应用场景:数据链路层差错检验】
送数据M,有k位;
除数P(对应一个生成多项式),有n位;
M右移n-1位的M';
计算M'/P的余数R(帧校验序列FCS);
发送帧:M’+FCS
计算余数的二进制除法(异或)
第一步:要在数据位(被除数)后边补 0 , 0 的个数比除数(生成多项式)少一位。
第二步:做除法(异或操作),从被除数的头五位减去五位的除数。除数的每一位都与被除数的对应位在不涉及上一位的情况下独立进行减法(实际进行的是模 2 加)。在本例中,除数 11001 与被除数的前五位 10110 进行的是模 2 加,得到 1111 (余数 1 前面的 0 被省略)。在被除数中下一个没有使用过的比特接着被抄录下来,使得余数的位数和除数的位数相同。如果位数不够,在商位补 0 (这与一般除法相同),因此,下一步就是 11110^11001 ,结果是 111 ,依次类推。在二进制除法中,除数总是以 1 开头的,然后从上一次的被除数 / 余数中与除数位数相同的部分中减去除数,并且只能从最左位是 1 的被除数 / 余数中减去除数。每当被除数 / 余数的最左位是 0 时,就在该步骤中把 0 丢弃,再把被除数中的下一个未使用比特抄录下来填充余数,同时对应的商数位补一个零,并按上述方法进行二进制除法运算,一直重复这个过程直到被除数中所有比特都被使用过。
余数 100 只有 3 位,而余数应为 4 位(比除数少一位),因此,取校验码时应在前面填一个 0 ,故其 CRC 校验码应为 0100 ,于是可求出该信息码的循环冗余码为 101100110100 。
为了判断传输的正确性,在接收端要有一个 CRC 校验器。它的功能和发生器一样,当收到 CRC 冗余校验码后,做同样的模 2 除法(注意,这里采用的生成多项式一定要与发送端相同)。如果余数是全 0 ,则说明传输正确;否则,传输错误,应重传。
【itoa函数可以将整型数字转为二进制字符串】
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 char res[33]; 5 unsigned int data,g,a[33]={0, 6 0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,0x00000080, 7 0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,0x00004000,0x00008000, 8 0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,0x00200000,0x00400000,0x00800000, 9 0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000,0x40000000,0x80000000 10 }; 11 unsigned int str_int(unsigned int *d) 12 { 13 unsigned int i=0,t=0; 14 char str[40]; 15 scanf("%s",str); 16 while (str[i]!='\0'){ 17 t<<=1; 18 t|=str[i]-48; 19 i++; 20 } 21 *d=t; 22 return i; 23 } 24 unsigned int GetData(unsigned int i){ return data&a[32-i+1]?1:0;} 25 int main() 26 { 27 unsigned int l1,l2,l3,r,i,cas; 28 printf("预处理多少条传送数据?\n"); 29 scanf("%d",&cas); 30 while (cas--){ 31 //读取待传送数据k位 32 printf("输入待传送数据M(不高于32位):"); 33 l1=str_int(&data); 34 //读取除数n位 35 printf("输入除数p(不高于%d位):",32-l1+1); 36 l2=str_int(&g); 37 //将待传送数据右移n-1位 38 data<<=(l2-1); 39 l1+=(l2-1); 40 //模2除求余数 41 r=0;i=32-l1+1; 42 while (i<=32){ 43 r<<=1; 44 r|=GetData(i); 45 if(r>=a[l2]) r^=g; 46 i++; 47 } 48 //输出结果 49 data>>=(l2-1); 50 printf("发送帧:%s",itoa(data,res,2)); 51 itoa(r,res,2); 52 l3=strlen(res); 53 for(i=l3;i<l2-1;i++) printf("0"); 54 printf("%s\n",res); 55 } 56 return 0; 57 }
找我内推: 字节跳动各种岗位
作者:
ZH奶酪(张贺)
邮箱:
cheesezh@qq.com
出处:
http://www.cnblogs.com/CheeseZH/
*
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。